/*  Date: 2011/4/8 11:00:00
 *  Revision: 2.5
 */

/*
 * This software program is licensed subject to the GNU General Public License
 * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html

 * (C) Copyright 2011 Bosch Sensortec GmbH
 * All Rights Reserved
 */


/* file BMA250.c
   brief This file contains all function implementations for the BMA250 in linux

*/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/init-input.h>

//#include <mach/system.h>
#include <mach/hardware.h>

#include <linux/gpio.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif

#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_PM)
#include <linux/pm.h>
#endif


enum {
	DEBUG_INIT = 1U << 0,
	DEBUG_CONTROL_INFO = 1U << 1,
	DEBUG_DATA_INFO = 1U << 2,
	DEBUG_SUSPEND = 1U << 3,
};
static u32 debug_mask = 0;
#define dprintk(level_mask, fmt, arg...)	if (unlikely(debug_mask & level_mask)) \
	printk(KERN_DEBUG fmt , ## arg)

module_param_named(debug_mask, debug_mask, int, 0644);


#define SENSOR_NAME                             "bma250"
#define GRAVITY_EARTH                           9806550
#define ABSMIN_2G                               (-GRAVITY_EARTH * 2)
#define ABSMAX_2G                               (GRAVITY_EARTH * 2)
#define SLOPE_THRESHOLD_VALUE                   32
#define SLOPE_DURATION_VALUE                    1
#define INTERRUPT_LATCH_MODE                    13
#define INTERRUPT_ENABLE                        1
#define INTERRUPT_DISABLE                       0
#define MAP_SLOPE_INTERRUPT                     2
#define SLOPE_X_INDEX                           5
#define SLOPE_Y_INDEX                           6
#define SLOPE_Z_INDEX                           7
#define BMA250_MAX_DELAY                        200
#define BMA150_CHIP_ID                          2
#define BMA250_CHIP_ID                          3
#define BMA250E_CHIP_ID                         0xF9
#define BMA250_RANGE_SET                        0
#define BMA250_BW_SET                           4


/*
 *
 *      register definitions
 *
 */

#define BMA250_CHIP_ID_REG                      0x00
#define BMA250_VERSION_REG                      0x01
#define BMA250_X_AXIS_LSB_REG                   0x02
#define BMA250_X_AXIS_MSB_REG                   0x03
#define BMA250_Y_AXIS_LSB_REG                   0x04
#define BMA250_Y_AXIS_MSB_REG                   0x05
#define BMA250_Z_AXIS_LSB_REG                   0x06
#define BMA250_Z_AXIS_MSB_REG                   0x07
#define BMA250_TEMP_RD_REG                      0x08
#define BMA250_STATUS1_REG                      0x09
#define BMA250_STATUS2_REG                      0x0A
#define BMA250_STATUS_TAP_SLOPE_REG             0x0B
#define BMA250_STATUS_ORIENT_HIGH_REG           0x0C
#define BMA250_RANGE_SEL_REG                    0x0F
#define BMA250_BW_SEL_REG                       0x10
#define BMA250_MODE_CTRL_REG                    0x11
#define BMA250_LOW_NOISE_CTRL_REG               0x12
#define BMA250_DATA_CTRL_REG                    0x13
#define BMA250_RESET_REG                        0x14
#define BMA250_INT_ENABLE1_REG                  0x16
#define BMA250_INT_ENABLE2_REG                  0x17
#define BMA250_INT1_PAD_SEL_REG                 0x19
#define BMA250_INT_DATA_SEL_REG                 0x1A
#define BMA250_INT2_PAD_SEL_REG                 0x1B
#define BMA250_INT_SRC_REG                      0x1E
#define BMA250_INT_SET_REG                      0x20
#define BMA250_INT_CTRL_REG                     0x21
#define BMA250_LOW_DURN_REG                     0x22
#define BMA250_LOW_THRES_REG                    0x23
#define BMA250_LOW_HIGH_HYST_REG                0x24
#define BMA250_HIGH_DURN_REG                    0x25
#define BMA250_HIGH_THRES_REG                   0x26
#define BMA250_SLOPE_DURN_REG                   0x27
#define BMA250_SLOPE_THRES_REG                  0x28
#define BMA250_TAP_PARAM_REG                    0x2A
#define BMA250_TAP_THRES_REG                    0x2B
#define BMA250_ORIENT_PARAM_REG                 0x2C
#define BMA250_THETA_BLOCK_REG                  0x2D
#define BMA250_THETA_FLAT_REG                   0x2E
#define BMA250_FLAT_HOLD_TIME_REG               0x2F
#define BMA250_STATUS_LOW_POWER_REG             0x31
#define BMA250_SELF_TEST_REG                    0x32
#define BMA250_EEPROM_CTRL_REG                  0x33
#define BMA250_SERIAL_CTRL_REG                  0x34
#define BMA250_CTRL_UNLOCK_REG                  0x35
#define BMA250_OFFSET_CTRL_REG                  0x36
#define BMA250_OFFSET_PARAMS_REG                0x37
#define BMA250_OFFSET_FILT_X_REG                0x38
#define BMA250_OFFSET_FILT_Y_REG                0x39
#define BMA250_OFFSET_FILT_Z_REG                0x3A
#define BMA250_OFFSET_UNFILT_X_REG              0x3B
#define BMA250_OFFSET_UNFILT_Y_REG              0x3C
#define BMA250_OFFSET_UNFILT_Z_REG              0x3D
#define BMA250_SPARE_0_REG                      0x3E
#define BMA250_SPARE_1_REG                      0x3F




#define BMA250_ACC_X_LSB__POS                   6
#define BMA250_ACC_X_LSB__LEN                   2
#define BMA250_ACC_X_LSB__MSK                   0xC0
#define BMA250_ACC_X_LSB__REG                   BMA250_X_AXIS_LSB_REG

#define BMA250_ACC_X_MSB__POS                   0
#define BMA250_ACC_X_MSB__LEN                   8
#define BMA250_ACC_X_MSB__MSK                   0xFF
#define BMA250_ACC_X_MSB__REG                   BMA250_X_AXIS_MSB_REG

#define BMA250_ACC_Y_LSB__POS                   6
#define BMA250_ACC_Y_LSB__LEN                   2
#define BMA250_ACC_Y_LSB__MSK                   0xC0
#define BMA250_ACC_Y_LSB__REG                   BMA250_Y_AXIS_LSB_REG

#define BMA250_ACC_Y_MSB__POS                   0
#define BMA250_ACC_Y_MSB__LEN                   8
#define BMA250_ACC_Y_MSB__MSK                   0xFF
#define BMA250_ACC_Y_MSB__REG                   BMA250_Y_AXIS_MSB_REG

#define BMA250_ACC_Z_LSB__POS                   6
#define BMA250_ACC_Z_LSB__LEN                   2
#define BMA250_ACC_Z_LSB__MSK                   0xC0
#define BMA250_ACC_Z_LSB__REG                   BMA250_Z_AXIS_LSB_REG

#define BMA250_ACC_Z_MSB__POS                   0
#define BMA250_ACC_Z_MSB__LEN                   8
#define BMA250_ACC_Z_MSB__MSK                   0xFF
#define BMA250_ACC_Z_MSB__REG                   BMA250_Z_AXIS_MSB_REG

#define BMA250_RANGE_SEL__POS                   0
#define BMA250_RANGE_SEL__LEN                   4
#define BMA250_RANGE_SEL__MSK                   0x0F
#define BMA250_RANGE_SEL__REG                   BMA250_RANGE_SEL_REG

#define BMA250_BANDWIDTH__POS                   0
#define BMA250_BANDWIDTH__LEN                   5
#define BMA250_BANDWIDTH__MSK                   0x1F
#define BMA250_BANDWIDTH__REG                   BMA250_BW_SEL_REG

#define BMA250_EN_LOW_POWER__POS                6
#define BMA250_EN_LOW_POWER__LEN                1
#define BMA250_EN_LOW_POWER__MSK                0x40
#define BMA250_EN_LOW_POWER__REG                BMA250_MODE_CTRL_REG

#define BMA250_EN_SUSPEND__POS                  7
#define BMA250_EN_SUSPEND__LEN                  1
#define BMA250_EN_SUSPEND__MSK                  0x80
#define BMA250_EN_SUSPEND__REG                  BMA250_MODE_CTRL_REG

#define BMA250_GET_BITSLICE(regvar, bitname)\
			((regvar & bitname##__MSK) >> bitname##__POS)


#define BMA250_SET_BITSLICE(regvar, bitname, val)\
	((regvar & ~bitname##__MSK) | ((val<<bitname##__POS)&bitname##__MSK))


/* range and bandwidth */

#define BMA250_RANGE_2G                         0
#define BMA250_RANGE_4G                         1
#define BMA250_RANGE_8G                         2
#define BMA250_RANGE_16G                        3


#define BMA250_BW_7_81HZ                        0x08
#define BMA250_BW_15_63HZ                       0x09
#define BMA250_BW_31_25HZ                       0x0A
#define BMA250_BW_62_50HZ                       0x0B
#define BMA250_BW_125HZ                         0x0C
#define BMA250_BW_250HZ                         0x0D
#define BMA250_BW_500HZ                         0x0E
#define BMA250_BW_1000HZ                        0x0F

/* mode settings */

#define BMA250_MODE_NORMAL                      0
#define BMA250_MODE_LOWPOWER                    1
#define BMA250_MODE_SUSPEND                     2



struct bma250acc{
	s16	x,
	y,
	z;
} ;

struct bma250_data {
	struct i2c_client *bma250_client;
	atomic_t delay;
	atomic_t enable;
	atomic_t int2_enable; //add by wff

	unsigned char mode;
	struct input_dev *input;
	struct bma250acc value;
	struct mutex value_mutex;
	struct mutex enable_mutex;
	struct mutex mode_mutex;
	struct delayed_work work;
	struct work_struct irq_work;
#ifdef CONFIG_HAS_EARLYSUSPEND
	struct early_suspend early_suspend;
#endif
#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_PM)
	unsigned char range_state;
	unsigned char bandwidth_state;
#endif
	int slope_th;
};

/* Addresses to scan */
static const unsigned short normal_i2c[] = {0x18, I2C_CLIENT_END};
static __u32 twi_id = 0;
static int i2c_num = 0;
static const unsigned short i2c_address[3] = {0x18,0x19,0x38};

#ifdef CONFIG_HAS_EARLYSUSPEND
static void bma250_early_suspend(struct early_suspend *h);
static void bma250_late_resume(struct early_suspend *h);
#endif

static struct sensor_config_info gsensor_info = {
	.input_type = GSENSOR_TYPE,
};

/**
 * gsensor_detect - Device detection callback for automatic device creation
 * return value:
 *                    = 0; success;
 *                    < 0; err
 */
static int gsensor_detect(struct i2c_client *client, struct i2c_board_info *info)
{
	struct i2c_adapter *adapter = client->adapter;
	int ret;

	dprintk(DEBUG_INIT, "%s enter \n", __func__);

	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
		return -ENODEV;

	if (twi_id == adapter->nr) {
		for (i2c_num = 0; i2c_num < (sizeof(i2c_address)/sizeof(i2c_address[0]));i2c_num++) {
			client->addr = i2c_address[i2c_num];
			pr_info("%s:addr= 0x%x,i2c_num:%d\n",__func__,client->addr,i2c_num);
			ret = i2c_smbus_read_byte_data(client,BMA250_CHIP_ID_REG);
			pr_info("Read ID value is :%d",ret);
			if ((ret &0x00FF) == BMA250_CHIP_ID) {
				pr_info("Bosch Sensortec Device detected!\n" );
				strlcpy(info->type, SENSOR_NAME, I2C_NAME_SIZE);
				return 0;

			} else if((ret &0x00FF) == BMA150_CHIP_ID) {

				pr_info("Bosch Sensortec Device detected!\n" \
					"BMA150 registered I2C driver!\n");
				strlcpy(info->type, SENSOR_NAME, I2C_NAME_SIZE);
				return 0;
			} else if((ret &0x00FF) == BMA250E_CHIP_ID) {

				pr_info("Bosch Sensortec Device detected!\n" \
					"BMA250E registered I2C driver!\n");
				strlcpy(info->type, SENSOR_NAME, I2C_NAME_SIZE);
				return 0;
			}
		}

		pr_info("%s:Bosch Sensortec Device not found, \
			maybe the other gsensor equipment! \n",__func__);
		return -ENODEV;
	} else {
		return -ENODEV;
	}
}

static int bma250_smbus_read_byte(struct i2c_client *client,
		unsigned char reg_addr, unsigned char *data)
{
	s32 dummy;
	dummy = i2c_smbus_read_byte_data(client, reg_addr);
	if (dummy < 0)
		return -1;
	*data = dummy & 0x000000ff;

	return 0;
}

static int bma250_smbus_write_byte(struct i2c_client *client,
		unsigned char reg_addr, unsigned char *data)
{
	s32 dummy;
	dummy = i2c_smbus_write_byte_data(client, reg_addr, *data);
	if (dummy < 0)
		return -1;
	return 0;
}

static int bma250_smbus_read_byte_block(struct i2c_client *client,
		unsigned char reg_addr, unsigned char *data, unsigned char len)
{
	s32 dummy;
	dummy = i2c_smbus_read_i2c_block_data(client, reg_addr, len, data);
	if (dummy < 0)
		return -1;
	return 0;
}

static int bma250_set_mode(struct i2c_client *client, unsigned char Mode)
{
	int comres = 0;
	unsigned char data1 = '\0';

	if (client == NULL) {
		comres = -1;
	} else{
		if (Mode < 3) {
			comres = bma250_smbus_read_byte(client,
					BMA250_EN_LOW_POWER__REG, &data1);
			switch (Mode) {
			case BMA250_MODE_NORMAL:
				data1  = BMA250_SET_BITSLICE(data1,
					BMA250_EN_LOW_POWER, 0);
				data1  = BMA250_SET_BITSLICE(data1,
					BMA250_EN_SUSPEND, 0);
				break;
			case BMA250_MODE_LOWPOWER:
				data1  = BMA250_SET_BITSLICE(data1,
					BMA250_EN_LOW_POWER, 1);
				data1  = BMA250_SET_BITSLICE(data1,
					BMA250_EN_SUSPEND, 0);
				break;
			case BMA250_MODE_SUSPEND:
				data1  = BMA250_SET_BITSLICE(data1,
					BMA250_EN_LOW_POWER, 0);
				data1  = BMA250_SET_BITSLICE(data1,
					BMA250_EN_SUSPEND, 1);
				break;
			default:
				break;
			}

			comres += bma250_smbus_write_byte(client,
					BMA250_EN_LOW_POWER__REG, &data1);
		} else{
			comres = -1;
		}
	}

	return comres;
}

static int bma250_get_mode(struct i2c_client *client, unsigned char *Mode)
{
	int comres = 0;

	if (client == NULL) {
		comres = -1;
	} else{
		comres = bma250_smbus_read_byte(client,
				BMA250_EN_LOW_POWER__REG, Mode);
		*Mode  = (*Mode) >> 6;
	}

	return comres;
}

static int bma250_set_range(struct i2c_client *client, unsigned char Range)
{
	int comres = 0;
	unsigned char data1 = '\0';

	if (client == NULL) {
		comres = -1;
	} else{
		if (Range < 4) {
			comres = bma250_smbus_read_byte(client,
					BMA250_RANGE_SEL_REG, &data1);
			switch (Range) {
			case 0:
				data1  = BMA250_SET_BITSLICE(data1,
						BMA250_RANGE_SEL, 0);
				break;
			case 1:
				data1  = BMA250_SET_BITSLICE(data1,
						BMA250_RANGE_SEL, 5);
				break;
			case 2:
				data1  = BMA250_SET_BITSLICE(data1,
						BMA250_RANGE_SEL, 8);
				break;
			case 3:
				data1  = BMA250_SET_BITSLICE(data1,
						BMA250_RANGE_SEL, 12);
				break;
			default:
					break;
			}
			comres += bma250_smbus_write_byte(client,
					BMA250_RANGE_SEL_REG, &data1);
		} else{
			comres = -1;
		}
	}

	return comres;
}

static int bma250_get_range(struct i2c_client *client, unsigned char *Range)
{
	int comres = 0;
	unsigned char data = '\0';

	if (client == NULL) {
		comres = -1;
	} else{
		comres = bma250_smbus_read_byte(client, BMA250_RANGE_SEL__REG,
				&data);
		data = BMA250_GET_BITSLICE(data, BMA250_RANGE_SEL);
		*Range = data;
	}

	return comres;
}


static int bma250_set_bandwidth(struct i2c_client *client, unsigned char BW)
{
	int comres = 0;
	unsigned char data = '\0';
	int Bandwidth = 0;

	if (client == NULL) {
		comres = -1;
	} else{
		if (BW < 8) {
			switch (BW) {
			case 0:
				Bandwidth = BMA250_BW_7_81HZ;
				break;
			case 1:
				Bandwidth = BMA250_BW_15_63HZ;
				break;
			case 2:
				Bandwidth = BMA250_BW_31_25HZ;
				break;
			case 3:
				Bandwidth = BMA250_BW_62_50HZ;
				break;
			case 4:
				Bandwidth = BMA250_BW_125HZ;
				break;
			case 5:
				Bandwidth = BMA250_BW_250HZ;
				break;
			case 6:
				Bandwidth = BMA250_BW_500HZ;
				break;
			case 7:
				Bandwidth = BMA250_BW_1000HZ;
				break;
			default:
					break;
			}
			comres = bma250_smbus_read_byte(client,
					BMA250_BANDWIDTH__REG, &data);
			data = BMA250_SET_BITSLICE(data, BMA250_BANDWIDTH,
					Bandwidth);
			comres += bma250_smbus_write_byte(client,
					BMA250_BANDWIDTH__REG, &data);
		} else{
			comres = -1;
		}
	}

	return comres;
}

static int bma250_get_bandwidth(struct i2c_client *client, unsigned char *BW)
{
	int comres = 0;
	unsigned char data = '\0';

	if (client == NULL) {
		comres = -1;
	} else{
		comres = bma250_smbus_read_byte(client, BMA250_BANDWIDTH__REG,
				&data);
		data = BMA250_GET_BITSLICE(data, BMA250_BANDWIDTH);
		if (data <= 8) {
			*BW = 0;
		} else{
			if (data >= 0x0F)
				*BW = 7;
			else
				*BW = data - 8;

		}
	}

	return comres;
}

static int bma250_read_accel_xyz(struct i2c_client *client,
							struct bma250acc *acc)
{
	int comres;
	unsigned char data[6] = {0};
	if (client == NULL) {
		comres = -1;
	} else{
		comres = bma250_smbus_read_byte_block(client,
				BMA250_ACC_X_LSB__REG, data, 6);

		acc->x = BMA250_GET_BITSLICE(data[0], BMA250_ACC_X_LSB)
			|(BMA250_GET_BITSLICE(data[1],
				BMA250_ACC_X_MSB)<<BMA250_ACC_X_LSB__LEN);
		acc->x = acc->x << (sizeof(short)*8-(BMA250_ACC_X_LSB__LEN
					+ BMA250_ACC_X_MSB__LEN));
		acc->x = acc->x >> (sizeof(short)*8-(BMA250_ACC_X_LSB__LEN
					+ BMA250_ACC_X_MSB__LEN));
		acc->y = BMA250_GET_BITSLICE(data[2], BMA250_ACC_Y_LSB)
			| (BMA250_GET_BITSLICE(data[3],
				BMA250_ACC_Y_MSB)<<BMA250_ACC_Y_LSB__LEN);
		acc->y = acc->y << (sizeof(short)*8-(BMA250_ACC_Y_LSB__LEN
					+ BMA250_ACC_Y_MSB__LEN));
		acc->y = acc->y >> (sizeof(short)*8-(BMA250_ACC_Y_LSB__LEN
					+ BMA250_ACC_Y_MSB__LEN));

		acc->z = BMA250_GET_BITSLICE(data[4], BMA250_ACC_Z_LSB)
			| (BMA250_GET_BITSLICE(data[5],
				BMA250_ACC_Z_MSB)<<BMA250_ACC_Z_LSB__LEN);
		acc->z = acc->z << (sizeof(short)*8-(BMA250_ACC_Z_LSB__LEN
					+ BMA250_ACC_Z_MSB__LEN));
		acc->z = acc->z >> (sizeof(short)*8-(BMA250_ACC_Z_LSB__LEN
					+ BMA250_ACC_Z_MSB__LEN));
	}

	return comres;
}

static void bma250_work_func(struct work_struct *work)
{
	struct bma250_data *bma250 = container_of((struct delayed_work *)work,
			struct bma250_data, work);
	static struct bma250acc acc;
	unsigned long delay = msecs_to_jiffies(atomic_read(&bma250->delay));

	bma250_read_accel_xyz(bma250->bma250_client, &acc);
	input_report_abs(bma250->input, ABS_X, acc.x);
	input_report_abs(bma250->input, ABS_Y, acc.y);
	input_report_abs(bma250->input, ABS_Z, acc.z);
	dprintk(DEBUG_DATA_INFO, "acc.x %d, acc.y %d, acc.z %d\n", acc.x, acc.y, acc.z);
	input_sync(bma250->input);
	mutex_lock(&bma250->value_mutex);
	bma250->value = acc;
	mutex_unlock(&bma250->value_mutex);
	schedule_delayed_work(&bma250->work, delay);
}

static ssize_t bma250_range_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	unsigned char data;
	struct i2c_client *client = to_i2c_client(dev);
	struct bma250_data *bma250 = i2c_get_clientdata(client);

	if (bma250_get_range(bma250->bma250_client, &data) < 0)
		return sprintf(buf, "Read error\n");

	dprintk(DEBUG_CONTROL_INFO, "%d, %s\n", data, __FUNCTION__);
	return sprintf(buf, "%d\n", data);
}

static ssize_t bma250_range_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long data;
	int error;
	struct i2c_client *client = to_i2c_client(dev);
	struct bma250_data *bma250 = i2c_get_clientdata(client);

	error = strict_strtoul(buf, 10, &data);
	if (error)
		return error;
	if (bma250_set_range(bma250->bma250_client, (unsigned char) data) < 0)
		return -EINVAL;

	return count;
}

static ssize_t bma250_bandwidth_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	unsigned char data;
	struct i2c_client *client = to_i2c_client(dev);
	struct bma250_data *bma250 = i2c_get_clientdata(client);

	if (bma250_get_bandwidth(bma250->bma250_client, &data) < 0)
		return sprintf(buf, "Read error\n");

	dprintk(DEBUG_CONTROL_INFO, "%d, %s\n", data, __FUNCTION__);
	return sprintf(buf, "%d\n", data);

}

static ssize_t bma250_bandwidth_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long data;
	int error;
	struct i2c_client *client = to_i2c_client(dev);
	struct bma250_data *bma250 = i2c_get_clientdata(client);

	error = strict_strtoul(buf, 10, &data);
	if (error)
		return error;
	if (bma250_set_bandwidth(bma250->bma250_client,
						 (unsigned char) data) < 0)
		return -EINVAL;

	return count;
}

static ssize_t bma250_mode_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	unsigned char data;
	struct i2c_client *client = to_i2c_client(dev);
	struct bma250_data *bma250 = i2c_get_clientdata(client);

	if (bma250_get_mode(bma250->bma250_client, &data) < 0)
		return sprintf(buf, "Read error\n");

	dprintk(DEBUG_CONTROL_INFO, "%d, %s\n", data, __FUNCTION__);
	return sprintf(buf, "%d\n", data);
}

static ssize_t bma250_mode_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long data;
	int error;
	struct i2c_client *client = to_i2c_client(dev);
	struct bma250_data *bma250 = i2c_get_clientdata(client);

	error = strict_strtoul(buf, 10, &data);
	if (error)
		return error;
	if (bma250_set_mode(bma250->bma250_client, (unsigned char) data) < 0)
		return -EINVAL;

	return count;
}


static ssize_t bma250_value_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct input_dev *input = to_input_dev(dev);
	struct bma250_data *bma250 = input_get_drvdata(input);
	struct bma250acc acc_value;

	mutex_lock(&bma250->value_mutex);
	acc_value = bma250->value;
	mutex_unlock(&bma250->value_mutex);

	dprintk(DEBUG_CONTROL_INFO, "x=%d, y=%d, z=%d ,%s\n", acc_value.x, acc_value.y, acc_value.z, __FUNCTION__);
	return sprintf(buf, "%d %d %d\n", acc_value.x, acc_value.y,
			acc_value.z);
}

static ssize_t bma250_delay_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct bma250_data *bma250 = i2c_get_clientdata(client);

	dprintk(DEBUG_CONTROL_INFO, "%d, %s\n", atomic_read(&bma250->delay), __FUNCTION__);
	return sprintf(buf, "%d\n", atomic_read(&bma250->delay));

}

static ssize_t bma250_delay_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long data;
	int error;
	struct i2c_client *client = to_i2c_client(dev);
	struct bma250_data *bma250 = i2c_get_clientdata(client);

	error = strict_strtoul(buf, 10, &data);
	if (error)
		return error;
	if (data > BMA250_MAX_DELAY)
		data = BMA250_MAX_DELAY;
	atomic_set(&bma250->delay, (unsigned int) data);

	return count;
}


static ssize_t bma250_enable_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct bma250_data *bma250 = i2c_get_clientdata(client);

	dprintk(DEBUG_CONTROL_INFO, "%d, %s\n", atomic_read(&bma250->enable), __FUNCTION__);
	return sprintf(buf, "%d\n", atomic_read(&bma250->enable));

}


//add by wff
static ssize_t bma250_int2_enable_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
      ssize_t temp = 0;
	  unsigned char data = '\0';

	  struct i2c_client *client1 = to_i2c_client(dev);
	  struct bma250_data *bma250 = i2c_get_clientdata(client1);
	  struct i2c_client *client = bma250->bma250_client;
	  int i;
	  temp =0;
	  for (i=0x09; i<0x3f; i++) {
	  	bma250_smbus_read_byte(client, i, &data);
		printk("--bma addr0x:%x- %x -\n",i, data);
	  }
//	  bma250_smbus_read_byte(client, BMA250_STATUS1_REG, &data);
//      printk("--BMA250_STATUS1_REG- %x -\n",data);
//	  bma250_smbus_read_byte(client, BMA250_STATUS2_REG, &data);
//      printk("--BMA250_STATUS2_REG- %x -\n",data);
//	  bma250_smbus_read_byte(client, BMA250_INT2_PAD_SEL_REG, &data);
//	  printk("--BMA250_INT2_PAD_SEL_REG- %x -\n",data);
//	  bma250_smbus_read_byte(client, BMA250_INT_DATA_SEL_REG, &data);
//	  printk("--BMA250_INT_DATA_SEL_REG- %x -\n",data);
//	  bma250_smbus_read_byte(client, BMA250_INT_SET_REG, &data);
//	  printk("--BMA250_INT_SET_REG- %x -\n",data);
      return sprintf(buf, "%d\n", temp);


}

static void bma250_set_enable(struct device *dev, int enable)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct bma250_data *bma250 = i2c_get_clientdata(client);
	int pre_enable = atomic_read(&bma250->enable);

	mutex_lock(&bma250->enable_mutex);
	if (enable) {
		if (pre_enable ==0) {
			bma250_set_mode(bma250->bma250_client,
							BMA250_MODE_NORMAL);
			schedule_delayed_work(&bma250->work,
				msecs_to_jiffies(atomic_read(&bma250->delay)));
			atomic_set(&bma250->enable, 1);
		}

	} else {
		if (pre_enable ==1) {
			bma250_set_mode(bma250->bma250_client,
							BMA250_MODE_SUSPEND);
			cancel_delayed_work_sync(&bma250->work);
			atomic_set(&bma250->enable, 0);
		}
	}
	mutex_unlock(&bma250->enable_mutex);

}

//add by wff bma250_smbus_read_byte
static void bma250_set_int2_enable(struct device *dev, unsigned char Mode)
{

	int comres = 0;
	unsigned char data1 = '\0';
	//struct bma250_data *bma250 = i2c_get_clientdata(client);
	struct i2c_client *client1 = to_i2c_client(dev);
	struct bma250_data *bma250 = i2c_get_clientdata(client1);
	struct i2c_client *client = bma250->bma250_client;

	if (client == NULL) {
		comres = -1;
	} else{
		if (Mode < 2) {

			if (0 == Mode)//¹Ø±Õ
			{
				data1 = 0x0a;	//bandwidth=31.25Hz update time : 16ms
				comres += bma250_smbus_write_byte(client, 0x10, &data1);
				data1 = 0x03;	//range (0x03 :2g  0x05:4g  0x08:8g  0x0c:16g)
				comres += bma250_smbus_write_byte(client, 0x0f, &data1);
				data1 = 0x07;	//disables single tap interrupt ;enables slope interrupt for x-axis,y-axis,z-axis
				comres += bma250_smbus_write_byte(client, 0x16, &data1);
				data1 = 0x00;
				comres += bma250_smbus_write_byte(client, 0x17, &data1);
				data1 = 0x00;	//unmaps single tap interrupt to INT1 pin
				comres += bma250_smbus_write_byte(client, 0x19, &data1);
				data1 = 0x00;
				comres += bma250_smbus_write_byte(client, 0x1a, &data1);
				data1 = 0x10;
				comres += bma250_smbus_write_byte(client, 0x28, &data1);
				data1 = 0x00;
				comres += bma250_smbus_write_byte(client, 0x1b, &data1);
				//Õð¶¯¿ª»úÁéÃô¶ÈÒÔ¼°Âö³å¿í¶ÈÉèÖÃ
				data1 = 0x04;
				comres += bma250_smbus_write_byte(client, BMA250_TAP_PARAM_REG, &data1);
				data1 = 0x1f;
				comres += bma250_smbus_write_byte(client, BMA250_TAP_THRES_REG, &data1);
				data1 = 0x09;
				comres += bma250_smbus_write_byte(client, BMA250_INT_SET_REG, &data1);


				/*
				//clear any latched interrupts
				printk("clear any latched interrupts --add by wff\n");
				data1 = 0x80;
				comres += bma250_smbus_write_byte(client, BMA250_INT_CTRL_REG, &data1);
				*/
			}
			else //Õý³£
			{
				data1 = 0x0a;	//bandwidth=31.25Hz update time : 16ms
				comres += bma250_smbus_write_byte(client, 0x10, &data1);
				data1 = 0x05;	//range (0x03 :2g  0x05:4g  0x08:8g  0x0c:16g)
				comres += bma250_smbus_write_byte(client, 0x0f, &data1);
				data1 = 0x07;	//enables single tap interrupt ;enables slope interrupt for x-axis,y-axis,z-axis
				comres += bma250_smbus_write_byte(client, 0x16, &data1);
				data1 = 0x00;
				comres += bma250_smbus_write_byte(client, 0x17, &data1);
				data1 = 0x20;	//maps single tap interrupt to INT1 pin
				comres += bma250_smbus_write_byte(client, 0x19, &data1);
				data1 = 0x00;
				comres += bma250_smbus_write_byte(client, 0x1a, &data1);
				data1 = 0x04;
				comres += bma250_smbus_write_byte(client, 0x1b, &data1);
				data1 = bma250->slope_th;
				comres += bma250_smbus_write_byte(client, 0x28, &data1);

				//Õð¶¯¿ª»úÁéÃô¶ÈÒÔ¼°Âö³å¿í¶ÈÉèÖÃ
				data1 = 0x07;
				comres += bma250_smbus_write_byte(client, 0x2a, &data1);
				data1 = 0x1f;
				comres += bma250_smbus_write_byte(client, 0x2b, &data1);
				data1 = 0x05;
				comres += bma250_smbus_write_byte(client, 0x20, &data1);
				data1 = 0x82;
				comres += bma250_smbus_write_byte(client, 0x21, &data1);

				/*
				//keep latched interrupts
				printk("keep latched interrupts --add by wff\n");
				data1 = 0x07;
				comres += bma250_smbus_write_byte(client, BMA250_INT_CTRL_REG, &data1);
				*/
			}

			//bma_dbg("%s: ret = %d Mode = %d . shake_boot --add by wff--\n", __FUNCTION__, comres, Mode);
			printk("%s: ret = %d Mode = %d . shake_boot --add by wff--\n", __FUNCTION__, comres, Mode);

		} else{
			comres = -1;
		}
	}

	return ;
}

static ssize_t bma250_enable_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long data;
	int error;

	error = strict_strtoul(buf, 10, &data);
	if (error)
		return error;
	if ((data == 0)||(data==1)) {
		bma250_set_enable(dev,data);
	}

	return count;
}

//add by wff
static ssize_t bma250_int2_enable_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{

	unsigned long data;
	int error;
	//struct i2c_client *client = to_i2c_client(dev); shake_boot
	//struct bma250_data *bma250 = i2c_get_clientdata(client);
    printk("%s buf : %s --add by wff--\n", __FUNCTION__, buf);
	error = strict_strtoul(buf, 10, &data);
	if (error)
		return error;
	//bma250_set_int2_enable(bma250->bma250_client, (unsigned char) data);
	bma250_set_int2_enable(dev, (unsigned char) data);
	return count;
}

static ssize_t bma250_slope_th_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct bma250_data *bma250 = i2c_get_clientdata(client);

	return sprintf(buf, "0x%x\n", bma250->slope_th);
}

static ssize_t bma250_slope_th_store(struct device *dev,
		struct device_attribute *attr,
		const char *buf, size_t count)
{
	unsigned long data;
	int error;
	struct i2c_client *client = to_i2c_client(dev);
	struct bma250_data *bma250 = i2c_get_clientdata(client);

	error = strict_strtoul(buf, 16, &data);
	if (error)
		return error;
	bma250->slope_th = data;
	return count;
}


static DEVICE_ATTR(range, S_IRUGO|S_IWUSR|S_IWGRP,
		bma250_range_show, bma250_range_store);
static DEVICE_ATTR(bandwidth, S_IRUGO|S_IWUSR|S_IWGRP,
		bma250_bandwidth_show, bma250_bandwidth_store);
static DEVICE_ATTR(mode, S_IRUGO|S_IWUSR|S_IWGRP,
		bma250_mode_show, bma250_mode_store);
static DEVICE_ATTR(value, S_IRUGO,
		bma250_value_show, NULL);
static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR|S_IWGRP,
		bma250_delay_show, bma250_delay_store);
static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR|S_IWGRP,
		bma250_enable_show, bma250_enable_store);

//add by wff
static DEVICE_ATTR(int2_enable, S_IRUGO|S_IWUGO,
		bma250_int2_enable_show, bma250_int2_enable_store);
static DEVICE_ATTR(slope_th, S_IRUGO|S_IWUGO,
		bma250_slope_th_show, bma250_slope_th_store);

static struct attribute *bma250_attributes[] = {
	&dev_attr_range.attr,
	&dev_attr_bandwidth.attr,
	&dev_attr_mode.attr,
	&dev_attr_value.attr,
	&dev_attr_delay.attr,
	&dev_attr_enable.attr,
	&dev_attr_int2_enable.attr,
	&dev_attr_slope_th.attr,
	NULL
};

static struct attribute_group bma250_attribute_group = {
	.attrs = bma250_attributes
};

static int bma250_input_init(struct bma250_data *bma250)
{
	struct input_dev *dev;
	int err;

	dev = input_allocate_device();
	if (!dev)
		return -ENOMEM;
	dev->name = SENSOR_NAME;
	dev->id.bustype = BUS_I2C;

	input_set_capability(dev, EV_ABS, ABS_MISC);
	input_set_abs_params(dev, ABS_X, ABSMIN_2G, ABSMAX_2G, 0, 0);
	input_set_abs_params(dev, ABS_Y, ABSMIN_2G, ABSMAX_2G, 0, 0);
	input_set_abs_params(dev, ABS_Z, ABSMIN_2G, ABSMAX_2G, 0, 0);
	input_set_drvdata(dev, bma250);

	err = input_register_device(dev);
	if (err < 0) {
		input_free_device(dev);
		return err;
	}
	bma250->input = dev;

	return 0;
}

static void bma250_input_delete(struct bma250_data *bma250)
{
	struct input_dev *dev = bma250->input;

	input_unregister_device(dev);
}

static int bma250_probe(struct i2c_client *client,
		const struct i2c_device_id *id)
{
	int err = 0;
	struct bma250_data *data;

	dprintk(DEBUG_INIT, "bma250: probe\n");

	dprintk(DEBUG_INIT, "bma250 probe i2c address is %d \n",i2c_address[i2c_num]);
	client->addr =i2c_address[i2c_num];

	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
		printk(KERN_INFO "i2c_check_functionality error\n");
		goto exit;
	}
	data = kzalloc(sizeof(struct bma250_data), GFP_KERNEL);
	if (!data) {
		err = -ENOMEM;
		goto exit;
	}

	i2c_set_clientdata(client, data);
	data->bma250_client = client;
	mutex_init(&data->value_mutex);
	mutex_init(&data->mode_mutex);
	mutex_init(&data->enable_mutex);
	bma250_set_bandwidth(client, BMA250_BW_SET);
	bma250_set_range(client, BMA250_RANGE_SET);

	INIT_DELAYED_WORK(&data->work, bma250_work_func);
	dprintk(DEBUG_INIT, "bma: INIT_DELAYED_WORK\n");
	atomic_set(&data->delay, BMA250_MAX_DELAY);
	atomic_set(&data->enable, 0);
	err = bma250_input_init(data);
	if (err < 0)
	{
		printk("bma: bma250_input_init err\n");
		goto kfree_exit;
	}
	err = sysfs_create_group(&data->input->dev.kobj,
						 &bma250_attribute_group);
	if (err < 0)
	{
		printk("bma: sysfs_create_group err\n");
		goto error_sysfs;
	}
#ifdef CONFIG_HAS_EARLYSUSPEND
	data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
	data->early_suspend.suspend = bma250_early_suspend;
	data->early_suspend.resume = bma250_late_resume;
	register_early_suspend(&data->early_suspend);
#endif
	data->slope_th = 0x05;
	dprintk(DEBUG_INIT, "bma250: probe end\n");

	return 0;

error_sysfs:
	bma250_input_delete(data);

kfree_exit:
	kfree(data);
exit:
	return err;
}

#ifdef CONFIG_HAS_EARLYSUSPEND
static void bma250_early_suspend(struct early_suspend *h)
{
	struct bma250_data *data =
		container_of(h, struct bma250_data, early_suspend);

	dprintk(DEBUG_SUSPEND, "bma250: early suspend\n");

	if (NORMAL_STANDBY == standby_type) {
		mutex_lock(&data->enable_mutex);
		if (atomic_read(&data->enable)==1) {
			bma250_set_mode(data->bma250_client, BMA250_MODE_SUSPEND);
			cancel_delayed_work_sync(&data->work);
		}
		mutex_unlock(&data->enable_mutex);
	} else if (SUPER_STANDBY == standby_type) {
		if (bma250_get_bandwidth(data->bma250_client, &data->bandwidth_state) < 0)
			printk("suspend: read bandwidth err\n");
		if (bma250_get_range(data->bma250_client, &data->range_state) < 0)
			printk("suspend: read range err\n");

		mutex_lock(&data->enable_mutex);
		if (atomic_read(&data->enable)==1) {
			bma250_set_mode(data->bma250_client, BMA250_MODE_SUSPEND);
			cancel_delayed_work_sync(&data->work);
		}
		mutex_unlock(&data->enable_mutex);
	}
}

static void bma250_late_resume(struct early_suspend *h)
{
	struct bma250_data *data =
		container_of(h, struct bma250_data, early_suspend);

	dprintk(DEBUG_SUSPEND, "bma250: late resume\n");

	if (NORMAL_STANDBY == standby_type) {
		mutex_lock(&data->enable_mutex);
		if (atomic_read(&data->enable)==1) {
			bma250_set_mode(data->bma250_client, BMA250_MODE_NORMAL);
			schedule_delayed_work(&data->work,
				msecs_to_jiffies(atomic_read(&data->delay)));
		}
		mutex_unlock(&data->enable_mutex);
	} else if (SUPER_STANDBY == standby_type) {
		if (bma250_set_bandwidth(data->bma250_client,
						 data->bandwidth_state) < 0)
			printk("suspend: write bandwidth err\n");
		if (bma250_set_range(data->bma250_client, data->range_state) < 0)
			printk("suspend: write range err\n");

		mutex_lock(&data->enable_mutex);
		if (atomic_read(&data->enable)==1) {
			bma250_set_mode(data->bma250_client, BMA250_MODE_NORMAL);
			schedule_delayed_work(&data->work,
				msecs_to_jiffies(atomic_read(&data->delay)));
		}
		mutex_unlock(&data->enable_mutex);

	}
}
#else
#ifdef CONFIG_PM
static int bma250_resume(struct i2c_client *client)
{
	struct bma250_data *data = i2c_get_clientdata(client);

	dprintk(DEBUG_SUSPEND, "bma250: resume\n");

	if (NORMAL_STANDBY == standby_type) {
		mutex_lock(&data->enable_mutex);
		if (atomic_read(&data->enable)==1) {
			bma250_set_mode(data->bma250_client, BMA250_MODE_NORMAL);
			schedule_delayed_work(&data->work,
				msecs_to_jiffies(atomic_read(&data->delay)));
		}
		mutex_unlock(&data->enable_mutex);
	} else if (SUPER_STANDBY == standby_type) {
		if (bma250_set_bandwidth(data->bma250_client,
						 data->bandwidth_state) < 0)
			printk("suspend: write bandwidth err\n");
		if (bma250_set_range(data->bma250_client, data->range_state) < 0)
			printk("suspend: write range err\n");

		mutex_lock(&data->enable_mutex);
		if (atomic_read(&data->enable)==1) {
			bma250_set_mode(data->bma250_client, BMA250_MODE_NORMAL);
			schedule_delayed_work(&data->work,
				msecs_to_jiffies(atomic_read(&data->delay)));
		}
		mutex_unlock(&data->enable_mutex);

	}
	return 0;
}

static int bma250_suspend(struct i2c_client *client, pm_message_t mesg)
{
	struct bma250_data *data = i2c_get_clientdata(client);

	dprintk(DEBUG_SUSPEND, "bma250: suspend\n");

	if (NORMAL_STANDBY == standby_type) {
		mutex_lock(&data->enable_mutex);
		if (atomic_read(&data->enable)==1) {
			bma250_set_mode(data->bma250_client, BMA250_MODE_SUSPEND);
			cancel_delayed_work_sync(&data->work);
		}
		mutex_unlock(&data->enable_mutex);
	} else if (SUPER_STANDBY == standby_type) {
		if (bma250_get_bandwidth(data->bma250_client, &data->bandwidth_state) < 0)
			printk("suspend: read bandwidth err\n");
		if (bma250_get_range(data->bma250_client, &data->range_state) < 0)
			printk("suspend: read range err\n");

		mutex_lock(&data->enable_mutex);
		if (atomic_read(&data->enable)==1) {
			bma250_set_mode(data->bma250_client, BMA250_MODE_SUSPEND);
			cancel_delayed_work_sync(&data->work);
		}
		mutex_unlock(&data->enable_mutex);
	}
	return 0;
}
#endif
#endif /* CONFIG_HAS_EARLYSUSPEND */

static int bma250_remove(struct i2c_client *client)
{
	struct bma250_data *data = i2c_get_clientdata(client);

	bma250_set_enable(&client->dev, 0);
#ifdef CONFIG_HAS_EARLYSUSPEND
	unregister_early_suspend(&data->early_suspend);
#endif
	sysfs_remove_group(&data->input->dev.kobj, &bma250_attribute_group);
	bma250_input_delete(data);
	i2c_set_clientdata(client, NULL);
	kfree(data);
	return 0;
}


static const struct i2c_device_id bma250_id[] = {
	{ SENSOR_NAME, 0 },
	{ }
};

MODULE_DEVICE_TABLE(i2c, bma250_id);

static struct i2c_driver bma250_driver = {
	.class = I2C_CLASS_HWMON,
	.driver = {
		.owner	= THIS_MODULE,
		.name	= SENSOR_NAME,
	},
	.id_table	= bma250_id,
	.probe		= bma250_probe,
	.remove		= bma250_remove,
#ifdef CONFIG_HAS_EARLYSUSPEND
#else
#ifdef CONFIG_PM
	.suspend	= bma250_suspend,
	.resume 	= bma250_resume,
#endif
#endif
	.detect		= gsensor_detect,
	.address_list	= normal_i2c,
};

static int __init BMA250_init(void)
{
	int ret = -1;
	dprintk(DEBUG_INIT, "bma250: init\n");

	if (input_fetch_sysconfig_para(&(gsensor_info.input_type))) {
		printk("%s: err.\n", __func__);
		return -1;
	} else
		twi_id = gsensor_info.twi_id;

	dprintk(DEBUG_INIT, "%s i2c twi is %d \n", __func__, twi_id);

	ret = i2c_add_driver(&bma250_driver);

	return ret;
}

static void __exit BMA250_exit(void)
{
	i2c_del_driver(&bma250_driver);
}

MODULE_AUTHOR("Albert Zhang <xu.zhang@bosch-sensortec.com>");
MODULE_DESCRIPTION("BMA250 driver");
MODULE_LICENSE("GPL");

module_init(BMA250_init);
module_exit(BMA250_exit);

